#pragma once

#include <iostream>
#include <string.h>
#include <functional>

#include "Common.hpp"
#include "InitAddr.hpp"
#include "Dictionary.hpp"

// 回调函数
using func_t = std::function<std::string(const std::string&)>;

// 服务器
namespace UdpServerArea
{
    using namespace InitAddrArea;
    using namespace LogArea;
    using namespace DictionaryArea;
    class UdpServer
    {
    public:
        UdpServer(func_t func, uint16_t port = defaultport) : _sockfd(defaultsocketfd)
            , _port(port)
            , _ip(iP)
            , _ser_addr(port)
            , _isrunning(false)
            ,_func_t(func)
        {
        }

        void InitUdpServer()
        {
            _sockfd = ::socket(AF_INET, SOCK_DGRAM, 0);
            if (_sockfd < 0)
            {
                LOG(LogLevel::FATALER) << "socket error";
                DIE(SOCKET_ERROR);
            }

            LOG(LogLevel::INFO) << "socket success, socketfd: " << _sockfd;

            // 将套接字与本地地址(Ip 和 端口号)绑定
            int n = ::bind(_sockfd, _ser_addr.GetAddr(), _ser_addr.Size());
            if (n < 0)
            {
                LOG(LogLevel::ERROR) << "bind error";
                DIE(BIND_ERROR);
            }

            LOG(LogLevel::INFO) << "bind success";
        }

        void Start()
        {
            // 创建 client 的 sockaddr_in, 用于 recvfrom 存放客户端的地址信息
            while (true)
            {
                char buffer[1024];
                struct sockaddr_in peer;
                socklen_t peerlen = sizeof(peer);
                memset(&peer, 0, sizeof(peer));
                // 从客户端收消息
                ssize_t n = ::recvfrom(_sockfd, buffer, sizeof(buffer) - 1, 0, CONV(&peer), &peerlen);
                if (n > 0)
                {
                    buffer[n] = 0;
                    // 使用实例化的 client 对象, 方便将 peer 中 port 和 ip 从网络转主机
                    InitAddr client(peer);

                    // 使用实例化的 client 对象, 方便将 peer 中 port 和 ip 从网络转主机
                    // 否则这里还要手动调用 ::inet_addr  ::ntohs
                    //  std::string cliinfo = client.GetIp() + ": " + std::to_string(client.GetPort()) + "# " + buffer;
                    //  LOG(LogLevel::INFO) << cliinfo;

                    // // 向客户端返回消息
                    // std::string message = "echo# ";
                    // message += cliinfo;
                    // ssize_t size = ::sendto(_sockfd, message.c_str(), message.size(), 0, CONV(&peer), sizeof(peer));

                    // 执行回调函数
                    std::string result = _func_t(buffer);
                    ::sendto(_sockfd, result.c_str(), result.size(), 0, CONV(&peer), sizeof(peer));
                }
            }
        }
        ~UdpServer()
        {
            if (_sockfd != defaultsocketfd)
                ::close(_sockfd);
        }

    private:
        int _sockfd;     // 套接字描述符
        int _port;       // 端口号
        std::string _ip; // ip地址
        InitAddr _ser_addr;
        bool _isrunning;

        func_t _func_t;
    };
}